<?php
/**
 * Smart Library - Smart Framework
 * http://smart-framework.highet.eu
 *
 * @category   SmartL
 * @package    SmartL_Config
 * @subpackage Storage
 * @copyright  Copyright (c) 2005-2008 Smart Framework team - Stepan Sindelar, Vojtech Vit
 * @license    http://www.opensource.org/licenses/bsd-license.php	New BSD License
 */

/**
 * @see SmartL_Config_Storage
 */
require_once 'SmartL/Config/Storage.php';

/** 
 * Custom implementation of storage that holds data of type "list".
 * 
 * @package SmartL_Config
 * @subpackage Storage
 */
class SmartL_Config_Storage_Array extends SmartL_Config_Storage {
	/**
	 * Name of tag used to add items to a "configuration list"     
	 */
	const CHILD_ADD_TAG = "add";
	/**
	 * Name of tag used to remove items from a "configuration list"     
	 */
	const CHILD_REMOVE_TAG = "remove";
	/**
	 * Name of tag used to update items from a "configuration list"
	 */
	const CHILD_UPDATE_TAG = "update";
	
	/**
	 * Returns children nodes.
	 * 
	 * @return array [string Index] => SmartL_Config_Storage 
	 */
	public function getData() {
		$array = $this->getChildren ();
		return $array [self::CHILD_ADD_TAG];
	}
	/**
	 * Adds element to configuration list (it may be only "add" or "remove" tag)
	 *
	 * @param string $name Tag name
	 * @param SmartL_Config_Storage $child Element to add to a list
	 */
	public function addChild($name, SmartL_Config_Storage $child) {
		$index = $child->getIndex ();
		if ($index === null) {
			require_once 'SmartL/Config/Storage/Exception.php';
			throw new SmartL_Config_Storage_Exception ( "List items must contain index attribute" );
		}
		
		if ($name == self::CHILD_ADD_TAG) {
			parent::addChild ( self::CHILD_ADD_TAG, $child );
		} else if ($name == self::CHILD_REMOVE_TAG) {
			if (isset ( $this->_children [self::CHILD_ADD_TAG] [$index] ))
				unset ( $this->_children [self::CHILD_ADD_TAG] [$index] );
		} else if ($name == self::CHILD_UPDATE_TAG) {
			if (! isset ( $this->_children [self::CHILD_ADD_TAG] [$index] )) {
				require_once 'SmartL/Config/Storage/Exception.php';
				throw new SmartL_Config_Storage_Exception ( "Tag with id {$index} wasn't found for updating." );
			}
		} else {
			require_once 'SmartL/Config/Storage/Exception.php';
			throw new SmartL_Config_Storage_Exception ( "Only \"" . self::CHILD_ADD_TAG . "\"" . " and \"" . self::CHILD_REMOVE_TAG . "\" tags are supported inside list" );
		}
	}
	/** 
	 * Recursively returns this node's data as an associative array.
	 * 
	 * This method overwrites method toArray() defined in parent class, but it 
	 * operates with the same parameters and returns the same type of results.      
	 *  
	 * @see SmartL_Config_Storage::toArray().
	 * @return array [string Index] => (string Node Value 
	 *               | array [string Child Index] => string Child value)
	 */
	public function toArray($convertNullToArray = true) {
		$result = array ();
		foreach ( $this->_children [self::CHILD_ADD_TAG] as $key => $child ) {
			$result [$key] = $child->toArray ( $convertNullToArray );
		}
		return $result;
	}
	
	/**
	 * Custom logic of children rewrite mode.
	 * Each children in list has rewriteMode=rewrite.
	 *
	 * @param string $childName Only for compatibility with interface.
	 * @return string
	 */
	public function getChildRewriteMode($childName) {
		return SmartL_Config_Storage::REWRITE_MODE_REWRITE;
	}
	
	//------------------------------------//
	//Implemented from interfaces 
	

	/**
	 * Implementation of Countable inteface.
	 * @return integer Count of children.
	 */
	public function count() {
		return count ( $this->_children [self::CHILD_ADD_TAG] );
	}
	
	/**
	 * Implementation of ArrayAccess interface.
	 * @param string $key Name of children.
	 * @return boolean True if child with given name exists.
	 */
	public function offsetExists($key) {
		return isset ( $this->_children [self::CHILD_ADD_TAG] [$key] );
	}
	
	/**
	 * Implementation of ArrayAccess interface.
	 * Unset child with given name.
	 * @param string $key Name of children.
	 */
	public function offsetUnset($key) {
		unset ( $this->_children [self::CHILD_ADD_TAG] [$key] );
	}
	
	/**
	 * Implementation of ArrayAccess interface.
	 * @param string $key Name of children.
	 * @return SmartL_Config_Storage|array[string|numeric]=>SmartL_Config_Storage Child|children with given name.
	 */
	public function offsetGet($key) {
		return $this->_children [self::CHILD_ADD_TAG] [$key];
	}
	
	/**
	 * Implementation of ArrayAccess interface.
	 * @param string $key Name of children.
	 * @param array[string|numeric]=>SmartL_Config_Storage|SmartL_Config_Storage $value new value of given offset.
	 */
	public function offsetSet($key, $value) {
		$this->_children [self::CHILD_ADD_TAG] [$key] = $value;
	}
	
	/**
	 * Implementation of Iterator interface.
	 * Resets internal pointer to first child.
	 */
	public function rewind() {
		reset ( $this->_children [self::CHILD_ADD_TAG] );
	}
	
	/**
	 * Implementation of Iterator interface.
	 * Moves internal pointer to next child.
	 * @return SmartL_Config_Storage|array[string|numeric]=>SmartL_Config_Storage The next child.
	 */
	public function next() {
		return next ( $this->_children [self::CHILD_ADD_TAG] );
	}
	
	/**
	 * Implementation of Iterator interface.
	 * @return SmartL_Config_Storage|array[string|numeric]=>SmartL_Config_Storage Current child.
	 */
	public function current() {
		return current ( $this->_children [self::CHILD_ADD_TAG] );
	}
	
	/**
	 * Implementation of Iterator interface.
	 * @return string Key=name of current child.
	 */
	public function key() {
		return key ( $this->_children [self::CHILD_ADD_TAG] );
	}
	
	/**
	 * Implementation of Iterator interface.
	 * @return boolean True, if the internal pointer is on valid position.
	 */
	public function valid() {
		return current ( $this->_children [self::CHILD_ADD_TAG] ) !== false;
	}
}